import qs from 'qs';
import { erroToText, toLabel, valueType, getFormData } from './request.config';

// 初始化配置
interface IRequestConfig {
    host: string; // API地址
    apiPath: string; // API目录
    photoPath: string; // 访问图片目录
    timeout: number; // 超时时间
    defaultConfig: any; // 默认配置
    interceptorsRequest: (url: string, config: any) => any; // 请求拦截
    interceptorsResponse: (url: string, config: any, res: any) => any; // 响应拦截
}

type IConfig = {
    label: string; // 日志类型
    method?: string; // 请求类型
    timeout?: number; // 请求超时
    [key: string]: any;
}

/**
 * 请求器
 * @param  {string}  url    请求地址
 * @param  {any}     data   请求数据
 * @param  {any}     config 请求配置
 * @return {Promise}        返回处理后的 Promise
 */
type TRequest = (
    url: string,
    data?: any,
    config?: IConfig | string
) => Promise<any>;

// 初始化请求模型
export default (config: IRequestConfig) => {
    const {
        host,
        apiPath,
        photoPath,
        timeout,
        defaultConfig,
        interceptorsRequest,
        interceptorsResponse,
    } = config;
    const baseURL = host + apiPath; // api地址前缀
    const photo = host + photoPath; // 图片访问地址前缀

    /**
     * 执行请求
     * @param  {string}  url    请求地址
     * @param  {any}     config 请求配置
     * @return {Promise}        返回处理后的 Promise
     */
    const request = (url: string, config?: any) => {
        // 拼接地址
        if (!/^http/.test(url)) url = baseURL + url;
        console.log(url)
        // 合并配置并执行请求拦截
        config = interceptorsRequest(url, {
            ...defaultConfig,
            ...config,
        });
        // 发出请求
        return Promise.race([
            // 追加请求超时
            fetch(url, config),
            new Promise((resolve:any, reject:any) => {
                setTimeout(
                    () => reject('request timeout'),
                    config.timeout || timeout
                );
            }),
        ])
            .then((response: any) => {
                // 转化响应数据
                return response[config.dataFormat]().then((res: any) => {
                    if (valueType.indexOf(typeof res) > -1) {
                        return Promise.reject('No JSON');
                    }
                    
                    return res;
                });
            })
            .catch((error: any) => {
                // 错误类型检查
                return Promise.resolve({
                    error,
                    errorText: erroToText(error),
                });
            })
            .then((res:any) => interceptorsResponse(url, config, res)); // 载入响应拦截
    };

    const get: TRequest = (address, data, config) => {
        const data_ = qs.stringify(data);
        return request(data_ ? `${address}?${data_}` : address, {
            data,
            address,
            ...toLabel(config),
        });
    };

    const post: TRequest = (address, data, config) => {
        return request(address, {
            method: 'post',
            data,
            address,
            ...toLabel(config),
        });
    };

    const put: TRequest = (address, data, config) => {
        return request(address, {
            method: 'put',
            data,
            address,
            ...toLabel(config),
        });
    };

    const del: TRequest = (address, data, config) => {
        return request(address, {
            method: 'delete',
            data,
            address,
            ...toLabel(config),
        });
    };

    const upload: TRequest = (address, data, config) => {
        return request(address, {
            method: 'post',
            headers: {},
            address,
            body: getFormData(data),
            data,
            ...toLabel(config),
        });
    };

    return {
        baseURL,
        photo,
        request,
        get,
        post,
        put,
        del,
        upload,
    };
};
